#!/usr/bin/env python
# -*- coding: utf-8 -*-

# lazy.py

# Copyright 2009-2010 Diego Hansen Hahn (aka DiegoHH) <diegohh90 [at] hotmail [dot] com>

# lazynds is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License.

# lazynds is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with lazynds. If not, see <http://www.gnu.org/licenses/>.

__author__ = "Diego Hansen Hahn"
__version__ = "v2.0.3"


import re
import mmap

import array
import collections
import heapq
import os
import sys
import shutil
import struct
import tempfile

import pygtk
pygtk.require('2.0')

import gtk
import gobject
import pango

import bios
import widgets
import areas
import pluginmanager

from structure import *

import dialogs
from images import images, palettes
from configobj import ConfigObj

import timedebugger

lazyTitle = "lazynds v2.0.3"

def filterlist(*args):
    filterlist = []
    for _filter in args:
        filter = gtk.FileFilter()
        filter.set_name(_filter[1])
        for pattern in _filter[2:]:
            filter.add_pattern(pattern)
        filterlist.append((_filter[0], filter))
    return filterlist

def populate_combo_box(cb, items):
    model = gtk.ListStore(gobject.TYPE_STRING)
    for x in items:
        model.append([x])
    cb.set_model(model)
    cell = gtk.CellRendererText()
    cb.pack_start(cell, True)
    cb.add_attribute(cell, 'text', 0)

class ActionStack(gobject.GObject):
    '''
    Funções redo/undo

    Funcionamento:

    São criadas dois stacks de tamanhos máximos 10. Sempre quando uma ação é realizada, ela é adicionada ao
    stack primário (fst_stack) e o stack secundário (scd_stack) é limpo (uma vez que, ao adicionar um nova ação,
    estaremos seguindo por um novo caminho).

    Para a função undo, a última ação realizada é retirada do stack primário, adicionada ao secundário e retornada.
    Para a função redo, a última ação desfeita é retirada do stack secundário, adicionada ao primário e retornada.

    Descrição da ação: ( Endereço, Original, Modificado, Descrição )

    Hansen
    '''

    maxlen = 50

    __gsignals__ = {'update': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())}

    def __init__(self):
        gobject.GObject.__init__(self)

        self.fst_stack = collections.deque(maxlen = ActionStack.maxlen)
        self.scd_stack = collections.deque(maxlen = ActionStack.maxlen)

    def append(self, action):
        self.fst_stack.append(action)
        self.scd_stack = collections.deque(maxlen = ActionStack.maxlen)
        self.emit('update')

    def undo(self):
        if self.fst_stack:
            action = self.fst_stack.pop()
            self.scd_stack.append(action)
        else:
            action = None
        self.emit('update')
        return action

    def redo(self):
        if self.scd_stack:
            action = self.scd_stack.pop()
            self.fst_stack.append(action)
        else:
            action = None
        self.emit('update')
        return action

    def clear(self):
        self.fst_stack = collections.deque(maxlen = ActionStack.maxlen)
        self.scd_stack = collections.deque(maxlen = ActionStack.maxlen)
        self.emit('update')


class Main:
    def __init__(self):
        if hasattr(sys, 'frozen'):
            self.local_path = os.path.realpath(os.path.dirname(sys.executable))
            #Adiciona o path local à engine de busca de módulos do python
            sys.path.append(self.local_path)
        else:
            self.local_path = os.path.realpath(os.path.dirname(__file__))

        self.__init_config_file()

        self.wtree_path = os.path.join(self.local_path, 'editor.ui')

        self.builder = gtk.Builder()
        self.builder.add_from_file(self.wtree_path)
        self.builder.connect_signals(self)

        self.main_window = self.builder.get_object('main_window')
        self.main_window.connect('destroy', gtk.main_quit)
#        self.main_window.connect('expose-event', self.teste)

        self.layout = self.builder.get_object('main_layout')

        self.stack = ActionStack()
        self.stack.connect('update', self.on_stack_update)

        self.menuitem_undo = self.builder.get_object('undo_item')
        self.menuitem_redo = self.builder.get_object('redo_item')
        self.menuitem_rescan = self.builder.get_object('rescan_item')

        self.menuitem_save = self.builder.get_object('save_file_item')
        self.menuitem_save_as = self.builder.get_object('save_as_file_item')

        self.__init_compressions()
        self.__init_dialogs()

        self.__init_builder_widgets()
        self.__init_control_area()
        self.__init_palette_area()
        self.__init_color_area()
        self.__init_viewer_area()

        self.main_window.connect('expose-event', self.on_main_window_expose)


        self.image_flag = True
        self.main_window.set_title(lazyTitle)
        self.main_window.maximize()
        self.main_window.show_all()

        self.hex_area.container.hide()
        self.hex_viewer.initialize_pixmaps()

        self.graphic_mode = True
        self.hexa_mode = False

        self.g_params_1 = {'position': self.graphic_area.container.get_property('position'),
                           'size': self.graphic_area.container.get_property('size')}

        self.h_params_1 = {'position': self.hex_area.container.get_property('position'),
                           'size': self.hex_area.container.get_property('size')}

        self.g_params_2 = {'position': (232, 20),
                           'size': (470, 390)}
        self.h_params_2 = {'position': (232, 440),
                           'size': (672, 90)}


# Não gostei!! Alterando...
    def on_main_window_expose(self, widget, event):
        # Arrumar
        alloc = self.layout.get_allocation()
        if self.graphic_mode and not self.hexa_mode:
            self.graphic_area.container.set_property('position', (220, 10))
            self.graphic_area.container.set_property('size', (alloc.width - (alloc.x + 2*215),alloc.height - (alloc.y + 10)))
            self.palette_area.container.set_property('position', (alloc.width - 200, 10))
        elif not self.graphic_mode and self.hexa_mode:
            self.hex_area.container.set_property('position', (220, 10))
            self.hex_area.container.set_property('size', (alloc.width - (alloc.x + 20 + 215),alloc.height - (alloc.y + 10)))

    def refresh(self):
        alloc = self.main_window.get_allocation()
        rect = gtk.gdk.Rectangle(0, 0, alloc.width, alloc.height)
        self.main_window.window.invalidate_rect(rect, True)
        self.main_window.window.process_updates(True)
        return False

    def __init_config_file(self):
        filename = "lazyConfig.ini"
        self.lazyConfig = ConfigObj(infile = filename,
                                    create_empty = True,
                                    unrepr = True)

    def __init_compressions(self):
        # Inicializa as listas com as compressões disponíveis durante a inicialização do lazynds
        self.lazyPluginsInfo = []
        for filename in os.listdir('plugins'):
            if re.match(r'^.*\.plg$', filename):
                self.lazyPluginsInfo.append(ConfigObj(os.path.join('plugins', filename), unrepr = True))

        pluginmanager.load_plugins(self.lazyPluginsInfo)

        self.lazyPluginsList = widgets.List("Plugins")
        for item in self.lazyPluginsInfo:
            self.lazyPluginsList.append(item["Name"],item["Prefix"])

        self.lazyBiosList = widgets.List("Rotinas da BIOS")
        for item in [('LZSS 0x10', 0x10),('LZSS 0x11', 0x11),
                     ('Huffman 4-Bits', 0x24),('Huffman 8-Bits', 0x28),('RLE', 0x30)]:
            self.lazyBiosList.append(*item)

        self.builder.get_object('scrolledwindow1').add(self.lazyPluginsList)
        self.builder.get_object('scrolledwindow2').add(self.lazyBiosList)

    def __init_dialogs(self):
        self.dlg_image = dialogs.Image(self.builder, self.main_window)
        self.dlg_compression = dialogs.Compression(self.builder, self.main_window)
        self.dlg_plugin = dialogs.Plugin(self.builder, self.main_window, self.lazyPluginsInfo)

    def __init_builder_widgets(self):
        self.data_control = widgets.BuilderContainer(self.layout, self.builder.get_object('vbox1'), 10,10)
        self.image_control = widgets.BuilderContainer(self.layout, self.builder.get_object('vbox3'), 10,310)
        self.palette_area = widgets.BuilderContainer(self.layout, self.builder.get_object('vbox8'), 725,10)

    def __init_control_area(self):
        self.img_index_range = self.builder.get_object('img_index')
        self.sb_id_1 = self.img_index_range.connect('value-changed', self.on_img_index_range_value_changed)

        self.img_width_range = self.builder.get_object('img_width')
        self.sb_id_2 = self.img_width_range.connect('value-changed', self.on_img_width_range_value_changed)

        self.img_height_range = self.builder.get_object('img_height')
        self.sb_id_5 = self.img_height_range.connect('value-changed', self.on_img_height_value_changed)

        self.img_offset_range = widgets.HexSpinButton()
        self.img_offset_range.set_size_request(60,-1)
        self.sb_id_3 = self.img_offset_range.connect('value-changed', self.on_img_offset_range_value_changed)

        self.builder.get_object('hbox4').pack_start(self.img_offset_range, True, True)

        self.lbl_padding_info = self.builder.get_object('lbl_padding')


    def __init_palette_area(self):
        self.palette = palettes.Palette()
        self.palette_widget = palettes.PaletteWidget()

        self.palette_widget.set_button_event_one(True)
        self.palette_widget.connect('one-click', self.on_palette_widget_one_click_event)

        # Adiciona 256 blocos de cores na paleta
        for i, y in enumerate(range(1, 161, 10)):
            for j, x in enumerate(range(1, 161, 10)):
                self.palette_widget.add_color(palettes.Colors(((i * 16) + (j + 1)), (0, 0, 0), (x, y)))

        box_mode_list = self.builder.get_object('box_mode_list')
        populate_combo_box(box_mode_list, [' Unidimensional', ' Bidimensional'])
        box_mode_list.set_active(0)
        box_mode_list.connect('changed', self.on_box_mode_list_changed)

        box_codec_list = self.builder.get_object('box_codec_list')
        populate_combo_box(box_codec_list, [' 1BPP Linear Reverso',
                                            ' 2BPP Linear Reverso',
                                            ' 4BPP Linear Reverso',
                                            ' 8BPP Linear'])
        box_codec_list.set_active(2)
        box_codec_list.connect('changed', self.on_box_codec_list_changed)

        self.box_palette_list = self.builder.get_object('box_palette_list')
        populate_combo_box(self.box_palette_list, [' Escala de Cinza',
                                                   ' Paleta Gravada na ROM',
                                                   ' Paleta Gravada no Buffer',
                                                   ' Paleta de Arquivo Externo'])
        self.box_palette_list.set_active(0)
        self.box_palette_list.connect('changed', self.on_box_palette_list_changed)

        self.pal_index_range = self.builder.get_object('pal_index_range')
        self.pal_index_range.set_adjustment(gtk.Adjustment(0, 0, 15, 1, 1, 0))
        self.pal_index_range.connect('changed', self.on_pal_index_range_value_changed)

        self.pal_offset_range = widgets.HexSpinButton()
        self.pal_offset_range.set_size_request(60,-1)
        self.builder.get_object('hbox9').pack_start(self.pal_offset_range, True, True)
        self.pal_offset_range.connect('value-changed', self.on_pal_offset_range_value_changed)
        self.pal_offset_range.set_sensitive(False)

    def __init_color_area(self):
        self.builder.get_object('vwp_palette').add(self.palette_widget)
        self.red_range = self.builder.get_object('red_range')
        self.blue_range = self.builder.get_object('blue_range')
        self.green_range = self.builder.get_object('green_range')
        self.color_label = self.builder.get_object('color_label')

        self.sg_id_1 = self.red_range.connect('value-changed', self.on_color_range_value_changed)
        self.sg_id_2 = self.green_range.connect('value-changed', self.on_color_range_value_changed)
        self.sg_id_3 = self.blue_range.connect('value-changed', self.on_color_range_value_changed)

    def __init_viewer_area(self):

        self.img_container = areas.ImageContainer((8, 8))
        self.img_container.set_palette(self.palette)
        self.img_container.connect('set-padding', self.set_padding_info)
        self.img_container.error_pixmap = os.path.join(self.local_path, 'pixmaps/error.png')

        self.img_widget = areas.GraphicWidget()
        self.img_widget.add_container(self.img_container)

        self.img_widget.props.has_tooltip = True
        self.img_widget.connect('query-tooltip', self.on_img_query_tooltip)

        box = self.builder.get_object('vbox16')
        box.pack_start(self.img_widget)

        self.graphic_area = widgets.BuilderContainer(self.layout, box, 220, 10, True)

        self.hscrollbar = self.builder.get_object('hscrollbar')
        self.sb_id_4 = self.hscrollbar.connect('adjust-bounds', self.on_hscrollbar_adjust_bounds)

        self.hex_viewer = areas.HexViewer()
        box = self.builder.get_object('hbox26')
        box.pack_start(self.hex_viewer)

        self.hex_area = widgets.BuilderContainer(self.layout, box, 220, 10, True)

        self.vscrollbar = self.builder.get_object('vscrollbar')
        self.vscrollbar.connect('adjust-bounds', self.on_vscrollbar_adjust_bounds)


    def __init_rom_parameters(self):
        index = 0

        self.lazyAddress = self.lazyBios.get_address(index)
        self.lazyFlag    = self.lazyBios.get_flag(index)
        self.lazyBuffer  = self.lazyBios.uncompress(self.lazyTemp, index)

        if self.lazyBuffer:
            self.lazyParameters = (self.lazyAddress,
                                   self.lazyBios.FLAGS.get(self.lazyFlag, self.lazyFlag),
                                   len(self.lazyBuffer),
                                   self.lazyTemp.tell() - self.lazyAddress)
        else:
            self.lazyParameters = (self.lazyAddress, "", -1, -1)

        self.lazySize = len(self.lazyBuffer)*(8/self.palette.get_codec())

        self.lazyWidth = 256
        self.lazyHeight = getHeight(self.lazySize, self.lazyWidth)

        # Iniciando um novo "projeto"
        # Desconectando os sinais paara depois reconectá-los
        self.img_width_range.disconnect(self.sb_id_2)
        self.img_height_range.disconnect(self.sb_id_5)
        self.img_index_range.disconnect(self.sb_id_1)
        self.img_offset_range.disconnect(self.sb_id_3)

        self.hscrollbar.disconnect(self.sb_id_4)

        self.hscrollbar.set_adjustment(gtk.Adjustment(0, 0, (self.lazyBios.size()-1), 1, 1, 0))
        self.hscrollbar.set_value(0)
        self.img_index_range.set_adjustment(gtk.Adjustment(0, 0, (self.lazyBios.size()-1), 1, 1, 0))
        self.img_index_range.set_value(0)
        self.img_offset_range.set_adjustment(gtk.Adjustment(0, 0, (self.lazyStat.st_size-1), 1, 16, 0))
        self.img_offset_range.set_value(self.lazyAddress)

        if self.img_container.is_mode(self.img_container.mode_1d):
            self.img_width_range.set_adjustment(gtk.Adjustment(0, 8, 800, 8, 8, 0))
            self.img_height_range.set_adjustment(gtk.Adjustment(0, 8, 800, 8, 8, 0))
        else:
            self.img_width_range.set_adjustment(gtk.Adjustment(0, 8, 800, (8/self.palette.get_codec()), 8, 0))
            self.img_height_range.set_adjustment(gtk.Adjustment(0, 8, 800, 1, 8, 0))

        self.img_width_range.set_value(self.lazyWidth)
        self.img_height_range.set_value(self.lazyHeight)

        self.sb_id_2 = self.img_width_range.connect('value-changed', self.on_img_width_range_value_changed)
        self.sb_id_5 = self.img_height_range.connect('value-changed', self.on_img_height_value_changed)
        self.sb_id_1 = self.img_index_range.connect('value-changed', self.on_img_index_range_value_changed)
        self.sb_id_3 = self.img_offset_range.connect('value-changed', self.on_img_offset_range_value_changed)
        self.sb_id_4 = self.hscrollbar.connect('adjust-bounds', self.on_hscrollbar_adjust_bounds)

        self.pal_offset_range.set_adjustment(gtk.Adjustment(0, 0, (self.lazyStat.st_size-1), 1, 512, 0))
        self.pal_offset_range.set_value(0)

        self.lazyModified = False

    def on_main_window_delete_event(self, widget, event):
        if hasattr(self, 'lazyModified'):
            if self.lazyModified:
                ret = dialogs.Warning(self.main_window, gtk.BUTTONS_YES_NO, "O arquivo foi modificado.\n\nSalvar alterações?")
                if ret:
                    self.on_save_file_item_activate(None)

        if hasattr(self, 'lazyFile'):
            self.lazyFile.close()
            self.lazyTemp.close()
            os.remove(self.lazyPath)

        # Apaga as cópias
        if hasattr(self, 'lazyPalette'):
            self.lazyPalette.close()

        return False

    def draw_new_palette(self):
        ''' Povoa a paleta com as cores '''
        ctrl = 0
        for color in self.palette_widget:
            color.set_color(self.palette[ctrl])
            ctrl += 1

        self.palette.set_palette_number(self.pal_index_range.get_value_as_int())
        self.palette_widget.refresh()

    def set_padding_info(self, widget, value):
        self.lbl_padding_info.set_text('%d' %value)

    def on_stack_update(self, widget):
        if len(self.stack.fst_stack) == 0:
            self.menuitem_undo.set_sensitive(False)
        else:
            self.menuitem_undo.set_sensitive(True)

        if len(self.stack.scd_stack) == 0:
            self.menuitem_redo.set_sensitive(False)
        else:
            self.menuitem_redo.set_sensitive(True)

    def change_original_data(self, address):
        self.lazyAddress = address

        bytes_to_read = self.lazyWidth * self.lazyHeight / (8/self.palette.get_codec())

        self.lazyTemp.seek(address, 0)
        self.lazyBuffer = array.array('c', self.lazyTemp.read(bytes_to_read))

        self.img_container.set_buffer(self.lazyBuffer, self.lazyWidth, self.lazyHeight)
        self.img_container.shift_value = 0

        if self.palette.is_palette_mode(self.palette.colors_buffer) and self.lazyBuffer:
            address = int(self.pal_offset_range.get_text(), 16)
            self.palette.generate_buffer_pal(self.lazyBuffer, address)
            self.palette.set_palette_mode(self.palette.colors_buffer)
            self.draw_new_palette()

        self.vscrollbar.set_adjustment(gtk.Adjustment(0, 0,(self.lazyStat.st_size/16)-1, 1, 12, 0))
        self.vscrollbar.set_value((address - address % 16)/16)
        self.hex_viewer.set_data((self.lazyTemp, self.lazyStat.st_size), (address - address % 16)/16)

        if self.graphic_mode:
            self.img_container.buffer2image()
            self.img_widget.refresh()
        if self.hexa_mode:
            self.hex_viewer.refresh()

    def change_compressed_data(self, index):
        if index > -1:
            self.lazyAddress = self.lazyBios.get_address(index)
            self.lazyFlag    = self.lazyBios.get_flag(index)
            self.lazyBuffer  = self.lazyBios.uncompress(self.lazyTemp, index)
        else:
            self.lazyBuffer = False

        if self.lazyBuffer:
            self.lazyParameters = (self.lazyAddress,
                                   self.lazyBios.FLAGS.get(self.lazyFlag, self.lazyFlag),
                                   len(self.lazyBuffer),
                                   self.lazyTemp.tell() - self.lazyAddress)
        else:
            self.lazyParameters = (self.lazyAddress, "", -1, -1)

        if self.lazyBuffer:
            self.lazySize = len(self.lazyBuffer)*(8/self.palette.get_codec())
            self.lazyHeight = getHeight(self.lazySize, self.lazyWidth)

        self.img_container.set_buffer(self.lazyBuffer, self.lazyWidth, self.lazyHeight)
        self.img_container.shift_value = 0

        if self.palette.is_palette_mode(self.palette.colors_buffer) and self.lazyBuffer:
            address = int(self.pal_offset_range.get_text(), 16)
            self.palette.generate_buffer_pal(self.lazyBuffer, address)
            self.palette.set_palette_mode(self.palette.colors_buffer)
            self.draw_new_palette()

        if self.lazyBuffer:
            self.vscrollbar.set_adjustment(gtk.Adjustment(0, 0, (len(self.lazyBuffer)/16)-1, 1, 12, 0))
            self.vscrollbar.set_value(0)
            self.hex_viewer.set_data((self.lazyBuffer.tostring(),len(self.lazyBuffer)),0)
        else:
            self.hex_viewer.set_data(("", 0), 0)

        if self.graphic_mode:
            self.img_container.buffer2image()
            self.img_widget.refresh()
        if self.hexa_mode:
            self.hex_viewer.refresh()

# Gerenciamento dos parâmetros do visualizador
# self.sb_id_1 : Spinbutton Índice
# self.sb_id_2 : Spinbutton Largura
# self.sb_id_3 : Spinbutton Endereço
# self.sb_id_4 : Scrollbar Índice
# self.sb_id_5 : Spinbutton Altura

    def on_vscrollbar_adjust_bounds(self, range, value):
        if self.image_flag:
            value = int(value) if (int(value) < (len(self.lazyBuffer)/16)-1) else (len(self.lazyBuffer)/16)-1
            value = value if value >= 0 else 0
        else:
            value = int(value) if (int(value) < self.lazyStat.st_size/16) else (self.lazyStat.st_size/16 - 1)
            value = value if value >= 0 else 0

        self.hex_viewer.set_start(value)
        self.hex_viewer.refresh()


    def on_hscrollbar_adjust_bounds(self, range, value):
        index = int(value) if (int(value) < self.lazyBios.size()) else (self.lazyBios.size() - 1)
        index = index if index >= 0 else 0

        self.change_compressed_data(index)

        self.img_index_range.disconnect(self.sb_id_1)
        self.img_index_range.set_value(index)
        self.sb_id_1 = self.img_index_range.connect('value-changed', self.on_img_index_range_value_changed)

        self.img_offset_range.disconnect(self.sb_id_3)
        self.img_offset_range.set_value(self.lazyAddress)
        self.sb_id_3 = self.img_offset_range.connect('value-changed', self.on_img_offset_range_value_changed)

    def on_img_index_range_value_changed(self, widget):
        index = widget.get_value_as_int()

        if self.image_flag:
            self.change_compressed_data(index)
        else:
            self.change_original_data(self.lazyBios.get_address(index))

        self.hscrollbar.disconnect(self.sb_id_4)
        self.hscrollbar.set_value(index)
        self.sb_id_4 = self.hscrollbar.connect('adjust-bounds', self.on_hscrollbar_adjust_bounds)

        self.img_offset_range.disconnect(self.sb_id_3)
        self.img_offset_range.set_value(self.lazyAddress)
        self.sb_id_3 = self.img_offset_range.connect('value-changed', self.on_img_offset_range_value_changed)

    def on_img_offset_range_value_changed(self, widget):
        address = int(widget.get_text(), 16)

        for index in range(self.lazyBios.size()):
            x = index if self.lazyBios.get_address(index) == address else -1
            if x != -1: break

        if self.image_flag:
            self.change_compressed_data(x)
        else:
            self.change_original_data(address)

        if x > -1:
            self.img_index_range.disconnect(self.sb_id_1)
            self.img_index_range.set_value(index)
            self.sb_id_1 = self.img_index_range.connect('value-changed', self.on_img_index_range_value_changed)

            self.hscrollbar.disconnect(self.sb_id_4)
            self.hscrollbar.set_value(index)
            self.sb_id_4 = self.hscrollbar.connect('adjust-bounds', self.on_hscrollbar_adjust_bounds)

    def on_img_width_range_value_changed(self, widget):

        width = widget.get_value_as_int()

        # Verificação da multiplicidade da largura
        if self.img_container.is_mode(self.img_container.mode_1d):
            self.lazyWidth = (width/8)*8
        else:
            self.lazyWidth = (width/(8/self.palette.get_codec()))*(8/self.palette.get_codec())

        self.lazySize = len(self.lazyBuffer)*(8/self.palette.get_codec())
        self.lazyHeight = getHeight(self.lazySize, self.lazyWidth)

        self.img_width_range.disconnect(self.sb_id_2)
        self.img_width_range.set_value(self.lazyWidth)
        self.img_height_range.set_value(self.lazyHeight)
        self.sb_id_2 = self.img_width_range.connect('value-changed', self.on_img_width_range_value_changed)

        if hasattr(self, 'lazyBuffer'):
            if not self.image_flag:
                index = int(self.img_offset_range.get_text(), 16)
                self.change_original_data(index)
            else:
                self.img_container.set_buffer(self.lazyBuffer, self.lazyWidth, self.lazyHeight)
                self.img_container.buffer2image()
                self.img_widget.refresh()

    def on_img_height_value_changed(self, widget):
        if not hasattr(self, 'lazyFile'):
            return

        self.lazyHeight = widget.get_value_as_int()
        if not self.image_flag:
            self.change_original_data(int(self.img_offset_range.get_text(), 16))

    def on_img_query_tooltip(self, widget, x, y, keyboard_mode, tooltip):
        if hasattr(self, 'lazyParameters'):
            if self.img_container.is_mouse_over((x,y)):
                address =   '<tt><b> Endereço:</b> %08X </tt>' %self.lazyParameters[0]
                comp =      '<tt><b> Compressão Usada:</b> %s </tt>' %self.lazyParameters[1]
                dec_size =  '<tt><b> Tamanho Descomprimido:</b> %d </tt>' %self.lazyParameters[2]
                enc_size =  '<tt><b> Tamanho Comprimido:</b> %d </tt>' %self.lazyParameters[3]
                tooltip.set_markup(comp + '\n' + dec_size + '\n' + enc_size + '\n' + address)
                return True
        return False

    def on_menu_chk_hex_toggled(self, widget):
        if widget.get_active():
            self.hexa_mode = True
            self.hex_area.container.show()

        else:
            self.hexa_mode = False
            self.hex_area.container.hide()
        self.refresh()

    def on_menu_chk_img_toggled(self, widget):
        if widget.get_active():
            self.img_container.buffer2image()
            self.graphic_mode = True
            self.graphic_area.container.show()
            self.image_control.container.show()
            self.palette_area.container.show()
        else:
            self.graphic_mode = False
            self.graphic_area.container.hide()
            self.image_control.container.hide()
            self.palette_area.container.hide()
        self.refresh()


    def on_menu_chk_all_toggled(self, widget):
        if widget.get_active():
            self.hex_area.container.set_property('position', self.h_params_2['position'])
            self.hex_area.container.set_property('size', self.h_params_2['size'])
            self.graphic_area.container.set_property('position', self.g_params_2['position'])
            self.graphic_area.container.set_property('size', self.g_params_2['size'])
            self.graphic_mode = True
            self.hexa_mode = True
            self.graphic_area.container.show()
            self.image_control.container.show()
            self.palette_area.container.show()
            self.hex_area.container.show()

            self.hex_viewer.refresh()
        else:
            self.h_params_2['position'] = self.hex_area.container.get_property('position')
            self.h_params_2['size'] = self.hex_area.container.get_property('size')
            self.g_params_2['position'] = self.graphic_area.container.get_property('position')
            self.g_params_2['size'] = self.graphic_area.container.get_property('size')
            self.graphic_mode = False
            self.hexa_mode = False
            self.graphic_area.container.hide()
            self.image_control.container.hide()
            self.palette_area.container.hide()
            self.hex_area.container.hide()

    def on_chk_decompress_image_toggled(self, widget):
        self.image_flag = widget.get_active()

        if self.image_flag:
            self.img_height_range.set_sensitive(False)
            self.hscrollbar.set_sensitive(True)
        else:
            self.img_height_range.set_sensitive(True)
            self.hscrollbar.set_sensitive(False)

        if not hasattr(self, 'lazyFile'):
            return False

        self.on_img_offset_range_value_changed(self.img_offset_range)

# Gerenciamento do controle de imagem
    def on_box_mode_list_changed(self, widget):
        self.img_container.toggle_mode()

        if self.img_container.is_mode(self.img_container.mode_1d):
            self.img_width_range.set_adjustment(gtk.Adjustment(0, 8, 800, 8, 8, 0))
            self.img_width_range.set_value((self.lazyWidth/8)*8)
        else:
            self.img_width_range.set_adjustment(gtk.Adjustment(0, 8, 800, (8/self.palette.get_codec()), 8, 0))
            self.img_width_range.set_value((self.lazyWidth/(8/self.palette.get_codec()))*(8/self.palette.get_codec()))


        if hasattr(self, 'lazyBuffer'):
            self.img_container.buffer2image()
            self.img_widget.refresh()


    def on_box_codec_list_changed(self, widget):
        self.palette.set_codec([1,2,4,8][widget.get_active()])
        self.palette.set_palette_mode(self.palette.mode)

        disp_palettes = 256 / 2**self.palette.get_codec() - 1
        self.pal_index_range.set_adjustment(gtk.Adjustment(0,0,disp_palettes,1,1,0))
        self.pal_index_range.set_value(0)


        if self.img_container.is_mode(self.img_container.mode_1d):
            self.img_width_range.set_adjustment(gtk.Adjustment(0, 8, 800, 8, 8, 0))
            self.img_width_range.set_value((self.lazyWidth/8)*8)
        else:
            self.img_width_range.set_adjustment(gtk.Adjustment(0, 8, 800, (8/self.palette.get_codec()), 8, 0))
            self.img_width_range.set_value((self.lazyWidth/(8/self.palette.get_codec()))*(8/self.palette.get_codec()))


        if hasattr(self, 'lazyBuffer'):
            self.draw_new_palette()
            self.img_container.set_buffer(self.lazyBuffer, self.lazyWidth, self.lazyHeight)
            self.img_container.buffer2image()
            self.img_widget.refresh()

    def on_box_palette_list_changed(self, widget):
        if not hasattr(self, 'lazyFile'):
            widget.set_active(0)
            return None

        mode = widget.get_active()
        if mode == self.palette.colors_gray:
            self.pal_offset_range.set_sensitive(False)
            self.palette.generate_grayscale_pal()
            self.palette.set_palette_mode(self.palette.colors_gray)
        elif mode == self.palette.colors_romfile:
            self.pal_offset_range.set_sensitive(True)
            address = int(self.pal_offset_range.get_text(), 16)
            self.palette.generate_pal_from_rom(self.lazyTemp, address)
            self.palette.set_palette_mode(self.palette.colors_romfile)
        elif mode == self.palette.colors_buffer:
            if not hasattr(self, 'lazyBuffer'):
                widget.set_active(0)
                return None
            self.pal_offset_range.set_sensitive(True)
            address = int(self.pal_offset_range.get_text(), 16)
            self.palette.generate_buffer_pal(self.lazyBuffer, address)
            self.palette.set_palette_mode(self.palette.colors_buffer)
        elif mode == self.palette.colors_extern:
            if not hasattr(self, 'lazyPalette'):
                widget.set_active(0)
                return None
            self.pal_offset_range.set_sensitive(False)
            self.palette.set_palette_mode(self.palette.colors_extern)

        self.draw_new_palette()
        self.pal_index_range.set_value(0)
        if hasattr(self, 'lazyBuffer'):
            self.img_container.buffer2image()
            self.img_widget.refresh()

    def on_pal_index_range_value_changed(self, widget):
        index = widget.get_value_as_int()
        self.palette.set_palette_number(index)

        if not hasattr(self, 'lazyBuffer'):
            return None

        self.img_container.buffer2image()
        self.img_widget.refresh()

    def on_pal_offset_range_value_changed(self, widget):
        mode = self.palette.get_palette_mode()
        if mode == self.palette.colors_romfile:
            if not hasattr(self, 'lazyFile'):
                return None
            address = int(widget.get_text(), 16)
            self.palette.generate_pal_from_rom(self.lazyTemp, address)
            self.palette.set_palette_mode(self.palette.colors_romfile)

        elif mode == self.palette.colors_buffer:
            if not hasattr(self, 'lazyBuffer'):
                return None
            address = int(widget.get_text(), 16)
            self.palette.generate_buffer_pal(self.lazyBuffer, address)
            self.palette.set_palette_mode(self.palette.colors_buffer)

        self.draw_new_palette()
        self.on_palette_widget_one_click_event(None)

        if not hasattr(self, 'lazyBuffer'):
            return None

        self.img_container.buffer2image()
        self.img_widget.refresh()

# Gerenciamento do widget de cores:
    def on_palette_widget_one_click_event(self, widget):
        if not hasattr(self, 'lazyFile'):
            return None

        if not self.palette_widget.previous_color:
            return None

        self.red_range.set_sensitive(True)
        self.green_range.set_sensitive(True)
        self.blue_range.set_sensitive(True)

        rgb = self.palette_widget.previous_color.get_color()

        # Desconectar os sinais para não ser chamado a atualização da paleta
        # durante a atualização dos valores dos spinbuttons
        self.red_range.disconnect(self.sg_id_1)
        self.green_range.disconnect(self.sg_id_2)
        self.blue_range.disconnect(self.sg_id_3)

        self.red_range.set_value(int(rgb[0] * 31))
        self.green_range.set_value(int(rgb[1] * 31))
        self.blue_range.set_value(int(rgb[2] * 31))
        self.color_label.set_text('%04Xh'
                                  % (((int(rgb[2] * 31) << 10) | (int(rgb[1] * 31) << 5) | int(rgb[0] * 31) ) & 0x7FFF))

        self.sg_id_1 = self.red_range.connect('value-changed', self.on_color_range_value_changed)
        self.sg_id_2 = self.green_range.connect('value-changed', self.on_color_range_value_changed)
        self.sg_id_3 = self.blue_range.connect('value-changed', self.on_color_range_value_changed)

    def on_color_range_value_changed(self, widget):
        rgb = (self.red_range.get_value()/31.0,
               self.green_range.get_value()/31.0,
               self.blue_range.get_value()/31)
        self.palette_widget.previous_color.set_color(rgb)
        self.palette_widget.refresh()
        self.palette.change_color(rgb, self.palette_widget.previous_color.id)

        self.color_label.set_text('%04Xh'
                                  % (((int(rgb[2] * 31) << 10) | (int(rgb[1] * 31) << 5) | int(rgb[0] * 31) ) & 0x7FFF))
        self.img_container.buffer2image()
        self.img_widget.refresh()

#    Obsoleto - Versão 2.0.3 - Hansen
#    def on_chk_transparent_color_toggled(self, widget):
#        if not hasattr(self, 'lazyBuffer'):
#            return None
#        if widget.get_active():
#            self.transparent = True
#            self.img_container.transparent = True
#        else:
#            self.transparent = False
#            self.img_container.transparent = False
#        self.img_container.buffer2image()
#        self.img_widget.refresh()

    def on_btn_byte_backward_clicked(self, widget):
        if not hasattr(self, 'lazyBuffer'):
            return None

        self.img_container.shift_value -= 1
        if self.img_container.shift_value < 0:
            self.img_container.shift_value = 0
        self.img_container.buffer2image()
        self.img_widget.refresh()

    def on_btn_byte_forward_clicked(self, widget):
        if not hasattr(self, 'lazyBuffer'):
            return None

        self.img_container.shift_value += 1
        if self.img_container.shift_value > len(self.lazyBuffer):
            self.img_container.shift_value = len(self.lazyBuffer)
        self.img_container.buffer2image()
        self.img_widget.refresh()

    def on_btn_tile_backward_clicked(self, widget):
        if not hasattr(self, 'lazyBuffer'):
            return None

        self.img_container.shift_value -= 8*self.palette.get_codec()
        if self.img_container.shift_value < 0:
            self.img_container.shift_value = 0
        self.img_container.buffer2image()
        self.img_widget.refresh()


    def on_btn_tile_forward_clicked(self, widget):
        if not hasattr(self, 'lazyBuffer'):
            return None

        self.img_container.shift_value += 8*self.palette.get_codec()
        if self.img_container.shift_value > len(self.lazyBuffer):
            self.img_container.shift_value = len(self.lazyBuffer)
        self.img_container.buffer2image()
        self.img_widget.refresh()

# Gerenciamento de dados
    def on_new_file_item_activate(self, widget):
        pass

    def on_open_file_item_activate(self, widget):
        _filterlist = filterlist(('all', 'Todos os Arquivos', '*'),
                                 ('sup', 'Todos os Arquivos Suportados (*.gba, *.nds)', '*.gba', '*.nds'),
                                 ('nds', 'Roms Nintendo DS (*.nds)', '*.nds'),
                                 ('gba', 'Roms GameBoy Advance (*.gba)', '*.gba'))

        if "RomFolder" in self.lazyConfig.dict():
            folder = self.lazyConfig["RomFolder"]
        else:
            folder = self.local_path

        filename, folder, usedfilter = dialogs.FileChooser(self.main_window, folder, _filterlist, 'open')

        self.lazyConfig["RomFolder"] = folder
        self.lazyConfig.write()

        if not filename:
            return None
        elif os.name == 'nt':
            filename = filename.encode('windows-1252')

        file = open(filename, 'r+b')

        fmap = mmap.mmap(file.fileno(), 0, access = mmap.ACCESS_READ)

        if isNds(file):
            type = ('nds', readNdsFat(file))
        elif isGba(file):
            type = ('gba',)
        else:
            type = None

        _bios = bios.bios()

        dialog = dialogs.Scan(self.builder, self.main_window, _bios)
        rc = dialog.run(fmap, self.lazyBiosList, self.lazyPluginsList)

        if not rc:
            return None
        elif not _bios:
            dialogs.Error(self.main_window, "Não foram encontrados dados comprimidos no arquivo.")
            return None

        if hasattr(self, 'lazyFile'):
            self.lazyFile.close()

        fmap.close()

        fd, path = tempfile.mkstemp()
        shutil.copy(file.name, path)

        self.lazyFile = file
        self.lazyTemp = os.fdopen(fd, 'w+b')
        self.lazyPath = path
        self.lazyStat = os.stat(path)

        self.lazyType = type
        self.lazyBios = _bios

        self.__init_rom_parameters()

        self.on_img_offset_range_value_changed(self.img_offset_range)

        self.draw_new_palette()

        self.menuitem_rescan.set_sensitive(True)
        self.menuitem_save.set_sensitive(True)
        self.menuitem_save_as.set_sensitive(True)

        self.main_window.set_title("%s - %s" %(lazyTitle, self.lazyFile.name))

    def on_save_file_item_activate(self, widget):
        if not hasattr(self, 'lazyFile'):
            return

        self.lazyFile.seek(0,0)

        shutil.copy(self.lazyPath, self.lazyFile.name)
        self.lazyFile.flush()

        dialogs.Warning(self.main_window, gtk.BUTTONS_OK, "Arquivo salvo com sucesso!")

        self.lazyModified = False
        self.main_window.set_title("%s - %s" %(lazyTitle, self.lazyFile.name))
        self.stack.clear()

    def on_save_as_file_item_activate(self, widget):
        if not hasattr(self, 'lazyFile'):
            return

        if "RomFolder" in self.lazyConfig.dict():
            folder = self.lazyConfig["RomFolder"]
        else:
            folder = self.local_path

        filename, folder, usedfilter = dialogs.FileChooser(self.main_window, folder, None, 'save')

        self.lazyConfig["RomFolder"] = folder
        self.lazyConfig.write()

        if not filename:
            return None
        elif os.name == 'nt':
            filename = filename.encode('windows-1252')

        shutil.copy(self.lazyPath, filename)

        # O novo arquivo salvo será agora o lazyFile
        self.lazyFile.close()
        self.lazyFile = open(filename, 'r+b')

        dialogs.Warning(self.main_window, gtk.BUTTONS_OK, "Arquivo salvo com sucesso!")

        self.lazyModified = False
        self.main_window.set_title("%s - %s" %(lazyTitle, self.lazyFile.name))

        self.stack.clear()


    def on_rescan_item_activate(self, widget):

        if not hasattr(self, 'lazyFile'):
            return None

        fmap = mmap.mmap(self.lazyFile.fileno(), 0, access = mmap.ACCESS_READ)

        _bios = bios.bios()

        dialog = dialogs.Scan(self.builder, self.main_window, _bios)
        rc = dialog.run(fmap, self.lazyBiosList, self.lazyPluginsList)

        if not rc:
            return None
        elif not _bios:
            dialogs.Error(self.main_window, "Não foram encontrados dados comprimidos no arquivo.")
            return None

        fmap.close()

        self.lazyBios = _bios

        self.__init_rom_parameters()

        self.on_img_offset_range_value_changed(self.img_offset_range)


    def on_quit_item_activate(self, widget):
        if hasattr(self, 'lazyFile'):
            self.lazyFile.close()
            self.lazyTemp.close()
            os.remove(self.lazyPath)

        if hasattr(self, 'lazyPalette'):
            self.lazyPalette.close()

        gtk.main_quit()

    def on_undo_item_activate(self, widget):
        actions = self.stack.undo()
        for action in actions:
            self.lazyTemp.seek(action[0], 0)
            self.lazyTemp.write(action[2].tostring())

        self.on_img_index_range_value_changed(self.img_index_range)
        self.on_box_palette_list_changed(self.box_palette_list)

    def on_redo_item_activate(self, widget):
        actions = self.stack.redo()
        for action in actions:
            self.lazyTemp.seek(action[0], 0)
            self.lazyTemp.write(action[1].tostring())

        self.on_img_index_range_value_changed(self.img_index_range)
        self.on_box_palette_list_changed(self.box_palette_list)

    def on_plugin_item_activate(self, widget):
        self.dlg_plugin.run()

    def on_about_item_activate(self, widget):
        dialogs.About(self.main_window).show()

    def on_btn_export_data_clicked(self, widget):
        if not hasattr(self, 'lazyBuffer'):
            return None

        _filterlist = filterlist(('all', 'Todos os Arquivos', '*'),
                                 ('bmp', 'Imagem de bitmap (*.bmp)', '*.bmp'),
                                 ('png', 'Imagem PNG (*.png)', '*.png'),
                                 ('bin', 'Arquivo Binário (*.bin)'))

        if "DataFolder" in self.lazyConfig.dict():
            folder = self.lazyConfig["DataFolder"]
        else:
            folder = self.local_path

        filename, folder, usedfilter = dialogs.FileChooser(self.main_window, folder, _filterlist, 'save')

        self.lazyConfig["DataFolder"] = folder
        self.lazyConfig.write()

        if not filename:
            return None
        elif os.name == 'nt':
            filename = filename.encode('windows-1252')

        # Recupera o filtro usado
        for filter in _filterlist:
            if filter[1].get_name() == usedfilter.get_name():
                extension = filter[0]

        if (extension != 'all') and (filename.split('.')[-1].lower() != ''):
            filename += '.' + extension.lower()

        extension = filename.split('.')[-1].lower()

        with open(filename, 'wb') as output:
            if extension in ('bmp', 'png'):
                w = images.Writer(self.img_container.get_size(), self.palette, self.palette.get_codec(), self.img_container.get_mode(), False)
                w.write(output, self.lazyBuffer, self.palette.get_codec(), extension.upper())
            else:
                self.lazyBuffer.tofile(output)

    def on_btn_import_data_clicked(self, widget):
        if not hasattr(self, 'lazyFile'):
            return None

        _filterlist = filterlist(('all', 'Todos os Arquivos (*.*)', '*'),
                                 ('bmp', 'Imagem de bitmap (*.bmp)', '*.bmp'),
                                 ('png', 'Imagem PNG (*.png)', '*.png'),
                                 ('bin', 'Arquivos Binários (*.bin, *.raw, *.dat)', '*.bin', '*.raw', '*.dat'))

        if "DataFolder" in self.lazyConfig.dict():
            folder = self.lazyConfig["DataFolder"]
        else:
            folder = self.local_path

        filename, folder, usedfilter = dialogs.FileChooser(self.main_window, folder, _filterlist, 'open')

        self.lazyConfig["DataFolder"] = folder
        self.lazyConfig.write()

        if not filename:
            return None
        elif os.name == 'nt':
            filename = filename.encode('windows-1252')

        extension = filename.split('.')[-1].lower()

        input = open(filename, 'rb')
        if extension in ('bmp', 'png'):
            data, palette = self.dlg_image.run(input)
        else:
            data = array.array('c', input.read())
            palette = None
        input.close()

        if not data:
            return None

        # Gera um temporário do buffer que será comprimido
        temp = tempfile.NamedTemporaryFile()
        if os.name == 'nt':
            data.tofile(temp.file)
        elif os.name == 'posix':
            data.tofile(temp)

        # Chama a janela de compressão
        self.dlg_compression.cmp_image_offset.set_adjustment(gtk.Adjustment(0, 0, (self.lazyStat.st_size-1), 4, 512, 0))
        self.dlg_compression.cmp_image_offset.set_value(self.lazyAddress)
        self.dlg_compression.palette_offset.set_adjustment(gtk.Adjustment(0, 0, (self.lazyStat.st_size-1), 4, 512, 0))
        self.dlg_compression.palette_offset.set_value(self.pal_offset_range.get_value())

        actions = self.dlg_compression.run(self.lazyTemp, temp, palette, self.lazyType, self.lazyBios, self.lazyPluginsInfo)

        temp.close()
        if not actions:
            return

        actions_list = []
        # Hora de tratar as ações
        # Elementos da actions_list:  [Endereço, Dado Modificado, Dado Original]
        #                             [ int, array, array ]
        if 'data' in actions:
            ret = True
            item = actions['data']

            if item[0] == self.lazyAddress and len(item[1]) > self.lazyParameters[3]:
                ret = dialogs.Warning(self.main_window, gtk.BUTTONS_YES_NO, '''Novo tamanho é maior do que o original.\n\nContinuar?''')
            if ret:
                # Adiciona o conteudo original da rom ao stack de ação
                self.lazyTemp.seek(item[0], 0)
                item.append(array.array('c', self.lazyTemp.read(len(item[1]))))
                # Grava o novo conteúdo
                self.lazyTemp.seek(item[0], 0)
                self.lazyTemp.write(item[1].tostring())
                self.lazyTemp.flush()

                self.lazyTemp.seek(item[0], 0)

                actions_list.append(item)
            else:
                return None
        else:
            return None

        if 'pointer' in actions:
            if self.lazyType[0] == 'gba':
                addresses = actions['pointer'][1]
                if addresses:
                    new_data_address = array.array('c', struct.pack('<L', actions['pointer'][0]))
                    for address in addresses:
                        self.lazyTemp.seek(address, 0)
                    # Salva o ponteiro antigo
                        old_data_address = array.array('c', self.lazyTemp.read(4))
                        self.lazyTemp.seek(address, 0)
                    # Grava o ponteiro novo
                        self.lazyTemp.write(new_data_address.tostring())
                        actions_list.append([address, new_data_address, old_data_address])
            elif self.lazyType[0] == 'nds':
                address = actions['pointer'][1]
                if address:
                    new_entry_start = array.array('c', struct.pack('<L', actions['pointer'][0]))
                    new_entry_end = array.array('c', struct.pack('<L', actions['pointer'][0] + len(self.lazyBuffer)))
                    # Guarda as entradas na FAT
                    self.lazyTemp.seek(address, 0)
                    old_entry_start = array.array('c', self.lazyTemp.read(4))
                    old_entry_end = array.array('c', self.lazyTemp.read(4))
                    self.lazyTemp.seek(address, 0)
                    self.lazyTemp.write(new_entry_start.tostring())
                    self.lazyTemp.write(new_entry_end.tostring())
                    actions_list.append([address, new_entry_start, old_entry_start])
                    actions_list.append([address + 4, new_entry_end, old_entry_end])
                    #Verifica o novo tamanho da ROM
                    self.lazyTemp.seek(0x80, 0)
                    old_rom_size = array.array('c', self.lazyTemp.read(4))
                    if struct.unpack('<L', new_entry_end)[0] > struct.unpack('<L', old_rom_size)[0]:
                        self.lazyTemp.seek(0x80, 0)
                        self.lazyTemp.write(new_entry_end.tostring())
                        actions_list.append([0x80, new_entry_end, old_rom_size])
                    # Corrige o checksum do header
                        self.lazyTemp.seek(0,0)
                        new_checksum = struct.pack('<H', Crc16(self.lazyTemp.read(0x15e)))
                        old_checksum = array.array('c', self.lazyTemp.read(2))
                        self.lazyTemp.seek(0x15e, 0)
                        self.lazyTemp.write(new_checksum.tostring())
                        actions_list.append([0x15e, new_checksum, old_checksum])
                    self.lazyTemp.flush()

# Consertar
        if 'palette' in actions:
            address = actions['palette'][0]
            data = actions['palette'][1]

            self.lazyTemp.seek(address, 0)
            original = array.array('c', self.lazyTemp.read(len(data)))
            self.lazyTemp.seek(address, 0)
            self.lazyTemp.write(data.tostring())
            self.lazyTemp.flush()

            actions_list.append([address, data, original])

        self.stack.append(actions_list)

        self.lazyModified = True
        self.main_window.set_title("%s *" % self.main_window.get_title())

        self.on_img_index_range_value_changed(self.img_index_range)
        self.on_box_palette_list_changed(self.box_palette_list)


    def on_btn_open_palette_file_clicked(self, widget):
        if not hasattr(self, 'lazyBuffer'):
            return None

        _filterlist = filterlist(('pal', 'Arquivo de paleta (*.pal)', '*.pal'),
                                 ('all', 'Todos os Arquivos (*.*)', '*.*'))

        if "PaletteFolder" in self.lazyConfig.dict():
            folder = self.lazyConfig["PaletteFolder"]
        else:
            folder = self.local_path

        filename, folder, usedfilter = dialogs.FileChooser(self.main_window, folder, _filterlist, 'open')

        self.lazyConfig["PaletteFolder"] = folder
        self.lazyConfig.write()

        if not filename:
            return None
        elif os.name == 'nt':
            filename = filename.encode('windows-1252')

        self.lazyPalette = open(filename, 'rb')
        self.palette.generate_pal_from_extern(self.lazyPalette)

        if self.box_palette_list.get_active() == self.palette.colors_extern:
            self.palette.set_palette_mode(self.palette.colors_extern)
            self.draw_new_palette()
            self.img_container.buffer2image()
            self.img_widget.refresh()

    def on_btn_save_palette_file_clicked(self, widget):
        if not hasattr(self, 'lazyBuffer'):
            return None

        _filterlist = filterlist(('pal', 'Arquivo de paleta (*.pal)', '*.pal'))

        if "PaletteFolder" in self.lazyConfig.dict():
            folder = self.lazyConfig["PaletteFolder"]
        else:
            folder = self.local_path

        filename, folder, usedfilter = dialogs.FileChooser(self.main_window, folder, _filterlist, 'save')

        self.lazyConfig["PaletteFolder"] = folder
        self.lazyConfig.write()

        if not filename:
            return None
        elif os.name == 'nt':
            filename = filename.encode('windows-1252')

        for filter in _filterlist:
            if filter[1].get_name() == usedfilter.get_name():
                extension = filter[0]

        if (filename.split('.')[-1].lower() != extension.lower()):
            filename += '.' + extension.lower()

        output = open(filename, 'wb')
        self.palette.tofile(output, self.palette)

        output.close()

    def on_btn_write_palette_file_clicked(self, widget):
        if not hasattr(self, 'lazyBuffer'):
            return None

        _filterlist = filterlist(('pal', 'Arquivo de paleta (*.pal)', '*.pal'))

        if "PaletteFolder" in self.lazyConfig.dict():
            folder = self.lazyConfig["PaletteFolder"]
        else:
            folder = self.local_path

        filename, folder, usedfilter = dialogs.FileChooser(self.main_window, folder, _filterlist, 'open')

        self.lazyConfig["PaletteFolder"] = folder
        self.lazyConfig.write()

        if not filename:
            return None
        elif os.name == 'nt':
            filename = filename.encode('windows-1252')

        input = open(filename, 'rb')
        colormap = self.palette.fromfile(input)
        input.close()

        buffer = array.array('c')
        for color in colormap:
            buffer.extend(palettes.tuple2gba(*color))

        address = int(self.pal_offset_range.get_text(), 16)
        self.lazyTemp.seek(address, 0)
        original = array.array('c', self.lazyTemp.read(len(buffer)))
        self.lazyTemp.seek(-len(buffer), 1)
        self.lazyTemp.write(buffer.tostring())

        self.stack.append([[address, buffer, original]])

        self.lazyModified = True
        self.main_window.set_title(self.main_window.get_title() + ' - *')

        self.on_box_palette_list_changed(self.box_palette_list)

def Run():
    import psyco
    psyco.full()

    gtk.gdk.threads_init()
    gtk.gdk.threads_enter()
    try:
        gtk.main()
    finally:
        gtk.gdk.threads_leave()

if __name__ == '__main__':
    Main()
    Run()
